package com.lam.code.configuration.shiro;

import cn.hutool.core.util.IdUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.lam.code.configuration.prop.JWTProperties;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;

/**
 * @author lam
 * @description jwt工具类
 * @date 2019/12/20 23:46
 */
@Component
public class JWTUtil {

    private static JWTProperties jwtProperties;

    @Resource
    public void setJwtProperties(JWTProperties jwtProperties) {
        JWTUtil.jwtProperties = jwtProperties;
    }


    /**
     * 获得Token中的信息无需secret解密也能获得
     *
     * @param token jwt-token
     * @param claim claim名
     * @return 具体信息
     */
    public static String getClaim(String token, String claim) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(claim).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 校验token是否正确
     *
     * @param token jwt-token
     * @return boolean
     */
    public static boolean verify(String token, String userCode, String salt) {
        Algorithm algorithm = Algorithm.HMAC256(salt);
        JWTVerifier verifier = JWT.require(algorithm)
                .withClaim(SecurityConstant.JWT_USERCODE , userCode)
                .build();
        verifier.verify(token);
        return true;
    }


    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的签发时间
     */
    public static Date getIssuedAt(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getIssuedAt();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获得token中的用户编码
     *
     * @return token中包含的用户编码
     */
    public static String getUserCode(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(SecurityConstant.JWT_USERCODE).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }


    /**
     * 生成签名,n分钟后过期
     *
     * @param userCode            用户编码
     * @return jwt
     */
    public static String sign(String userCode) {
        String secret = getSalt(userCode);
        // 此处过期时间，单位：毫秒
        Date date = new Date(System.currentTimeMillis() + jwtProperties.getTokenExpireTime() * 60 * 1000L);
        Algorithm algorithm = Algorithm.HMAC256(secret);

        return JWT.create()
                .withClaim(SecurityConstant.JWT_USERCODE, userCode)
                .withJWTId(IdUtil.simpleUUID())
                .withExpiresAt(date)
                .withIssuedAt(new Date())
                .sign(algorithm);
    }

    /**
     * token是否过期
     *
     * @return true：过期
     */
    public static boolean isTokenExpired(String token) {
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getExpiresAt().before(Calendar.getInstance().getTime());
    }

    /**
     * 获取盐 （userCode加JWT私钥加密）
     * @param userCode 用户ID
     * @return
     */
    public static String getSalt(String userCode){
        return userCode + jwtProperties.getEncryptSalt();
    }

    /**
     * 生成随机盐,长度32位
     *
     * @return
     */
    public static String generateSalt() {
        SecureRandomNumberGenerator secureRandom = new SecureRandomNumberGenerator();
        String hex = secureRandom.nextBytes(16).toHex();
        return hex;
    }

}
